/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-11-24
 * Time: 21:25
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Diagnostics;
using System.Collections.Generic;

using tools;

using Labb4.Entity;
using Labb4.Main;
using Labb4.Pooman.Cards;
using Labb4.Pooman.Game;

namespace Labb4.Pooman.Players
{
	/// <summary>
	/// A player, wraps two hands (phase 1 hand and pahse 2 hand), a controler, and a card area
	/// </summary>
	public class Player : IBasicHand
	{
		#region members
		
		/// <summary>
		/// Different constants used when evaluating the quality of won cards
		/// </summary>
		public enum Evaluation
		{
			BAD = 16,
			GOOD = 32,
			GREAT = 64,
			NA = 128,
			
			LOW_CARD_LIMIT = 7,
			HIGH_CARD_LIMIT = 12,
			
			GREAT_CONNECTION_LIMIT = 3
		}
		
		/// <summary>
		/// The hand used for playing phase 1 of the game
		/// </summary>
		private Hand				m_HandPhase1;
		/// <summary>
		/// The hand used for playing phase 2 of the game
		/// </summary>
		private Hand				m_HandPhase2;
		/// <summary>
		/// Reference to the current hand
		/// </summary>
		private HandProxy			m_CurrentHand;
		/// <summary>
		/// The controler controling this player
		/// </summary>
		private PoomanControl		m_Controler;
		/// <summary>
		/// Reference to the card area this players cards are graphically displayed in
		/// </summary>
		private CardArea			m_Area;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members, binds the controler to this player, sets the
		/// current hand, and registers this player with the player manager
		/// </summary>
		/// <param name="controler">The controler top set to this player</param>
		/// <param name="area">The card area to set to this player</param>
		public Player(PoomanControl controler, CardArea area)
		{
			m_HandPhase1 = new Hand();
			m_HandPhase2 = new Hand();
			m_CurrentHand = new HandProxy();
			
			m_Controler = controler;
			m_Controler.ControlledPlayer = this;
			m_CurrentHand.ProxyHand = m_HandPhase1;
			
			m_Area = area;
			
			PlayerManager.Instance.AddPlayer(this);
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Spaces out the graphical representations of the cards on the current hand evenly over
		/// the assigned graphical area
		/// </summary>
		public void PositionCards()
		{
			foreach(Card it in m_CurrentHand.ProxyHand.Cards)
			{
				it.GraphicalRepresentation.Pic.SelectAnimation(m_Controler.DisplayType());
			}
			
			m_Area.PositionCards(m_CurrentHand.ProxyHand.Cards);
		}
		
		/// <summary>
		/// Adds whatever cards are left in hand 1 to hand 2, and then switches the active hand to hand 2.
		/// But only if the current hand is hand 1. Otherwise nothing happens.
		/// </summary>
		public void SwitchToHand2(string displayMode)
		{
			if(m_CurrentHand.ProxyHand == m_HandPhase1)
			{
				m_HandPhase2.Cards.Add(m_HandPhase1.Cards);
				m_HandPhase2.Cards.ResetAllCards();
				
				foreach(Card it in m_HandPhase2.Cards)
				{
					it.GraphicalRepresentation.Pic.Activate(0);
					it.GraphicalRepresentation.Pic.SelectAnimation(displayMode);
				}
				
				m_HandPhase2.Cards.Sort();
				m_CurrentHand.ProxyHand = m_HandPhase2;
			}
		}
		
		/// <summary>
		/// Sets the current hand to hand 1
		/// </summary>
		public void SwitchToHand1()
		{
			if(m_HandPhase1.Cards.Count != 0)
			{
				//This has never happened
				Debug.WriteLine("When switching to hand 1, it was not empty.. Just thought I'd let you know.");
			}
			
			m_CurrentHand.ProxyHand = m_HandPhase1;
		}
		
		/// <summary>
		/// Takes the cards in the given card pile and adds them to hand 2.
		/// Also evaluates if these cards were concidered good, and plays an event accordingly
		/// </summary>
		/// <param name="cards"></param>
		public void TakeCards(CardPile cards)
		{
			Evaluation eval = m_Controler.EvaluateWonCards(cards);
			
			if(eval != Evaluation.NA)
			{
				m_Area.PlayWonCardsEvent(Properties.Instance.StartPath + "resources\\configfiles\\events\\event_took_" + eval.ToString().ToLower() + "_cards_");
			}
			
			m_HandPhase2.Cards.Add(cards);
		}
		
		/// <summary>
		/// Takes the cards in the given card pile and adds them to the current hand
		/// Also plays a "took bad cards" event
		/// </summary>
		/// <param name="cards"></param>
		public void PickupCards(CardPile cards)
		{
			m_Area.PlayPickedUpCardsEvent(Properties.Instance.StartPath + "resources\\configfiles\\events\\event_took_bad_cards_");
			
			foreach(Card it in cards)
			{
				it.GraphicalRepresentation.Pic.Activate(0);
				it.GraphicalRepresentation.Pic.SelectAnimation(m_Controler.DisplayType());
				m_CurrentHand.ProxyHand.Cards.Add(it);
			}
		}
		
		/// <summary>
		/// Removes all cards from all hands
		/// </summary>
		public void ClearAllCards()
		{
			m_HandPhase1.Cards.Clear();
			m_HandPhase2.Cards.Clear();
			
			if((m_HandPhase1.Cards.Count + m_HandPhase2.Cards.Count) > 0)
			{
				//this has never happened
				Debug.WriteLine("The cardpiles were not emptied..");
			}
		}
		
		/// <summary>
		/// Evaluates if the cards are good or bad on a value base
		/// </summary>
		/// <param name="cards">The cards to evaluate</param>
		/// <returns>An enum constant representing the quality of the cards</returns>
		public Evaluation EvaluateBasedOnValue(CardPile cards)
		{
			bool lowCards = false;
			bool highCards = false;
			
			foreach(Card it in cards)
			{
				if(it.ValueOfCard <= (int)Evaluation.LOW_CARD_LIMIT)
				{
					lowCards = true;
				}
				
				if(it.ValueOfCard >= (int)Evaluation.HIGH_CARD_LIMIT)
				{
					highCards = true;
				}
			}
			
			Evaluation eval = Evaluation.NA;
			
			if(lowCards)
			{
				if(highCards)
				{
					//good
					eval = Evaluation.GOOD;
				}
				else
				{
					//bad
					eval = Evaluation.BAD;
				}
			}
			else
			{
				if(highCards)
				{
					//great
					eval = Evaluation.GREAT;
				}
				else
				{
					//good
					eval = Evaluation.GOOD;
				}
			}
			
			return eval;
		}
		
		/// <summary>
		/// Evaluates if the cards are good or bad on a suit base
		/// </summary>
		/// <param name="cards">The cards to evaluate</param>
		/// <returns>An enum constant representing the quality of the cards</returns>
		public Evaluation EvaluateBasedOnSuit(CardPile cards)
		{
			AiGameStatePhase1Suit ai = new AiGameStatePhase1Suit();
			int distance = 0;
			
			foreach(Card it in cards)
			{
				distance += ai.Distance(it, m_HandPhase2.Cards);
			}
			
			Evaluation eval = Evaluation.NA;
			
			if(distance == cards.Count)
			{
				eval = Evaluation.GREAT;
			}
			else
			{
				if(distance > (cards.Count * 2))
				{
					eval = Evaluation.BAD;
				}
				else
				{
					eval = Evaluation.GOOD;
				}
			}
			
			return eval;
		}
		
		/// <summary>
		/// Saves this player to a List of string
		/// </summary>
		/// <param name="fileContent">The List of string to save this player to</param>
		/// <param name="player">The name of this player</param>
		public void Save(List<string> fileContent, string player)
		{
			int currentHand = 1;
			
			if(m_CurrentHand.ProxyHand == m_HandPhase2)
			{
				currentHand = 2;
			}
			
			fileContent.Add(player + "_current_hand " + currentHand.ToString());
			
			m_HandPhase1.Save(fileContent, player, "hand1", m_Controler.DisplayType());
			m_HandPhase2.Save(fileContent, player, "hand2", m_Controler.DisplayType());
		}
		
		/// <summary>
		/// Loads this player from a file
		/// </summary>
		/// <param name="config">The file to load from</param>
		/// <param name="player">The name of the player to load</param>
		public void Load(Config config, string player)
		{
			m_HandPhase1.Load(config, player, "hand1");
			m_HandPhase2.Load(config, player, "hand2");
			
			int currentHand = 0;
			
			if(MainForm.ErrorCheck(config.GetInt(player + "_current_hand", ref currentHand)))
			{
				if(currentHand == 1)
				{
					m_CurrentHand.ProxyHand = m_HandPhase1;
				}
				else
				{
					if(currentHand == 2)
					{
						m_CurrentHand.ProxyHand = m_HandPhase2;
					}
					else
					{
						Debug.WriteLine("WARNING!!!!! Loading player " + player + " did not select a current hand..");
					}
				}
			}
		}
		
		#endregion
		
		#region implemented interface methods
		
		/// <summary>
		/// Highlights a card at the given screen coordinates
		/// </summary>
		/// <param name="x">The x coordinate to attempt highlighting a card at</param>
		/// <param name="y">The y coordinate to attempt highlighting a card at</param>
		public void HighlightCard(ref int x, ref int y)
		{
			m_CurrentHand.HighlightCard(ref x, ref y);
		}
		
		/// <summary>
		/// Selects a card at the given screen coordinates
		/// </summary>
		/// <param name="x">The x coordinate to attempt selecting a card at</param>
		/// <param name="y">The y coordinate to attempt selecting a card at</param>
		public void SelectCard(ref int x, ref int y)
		{
			m_CurrentHand.SelectCard(ref x, ref y);
		}
		
		/// <summary>
		/// Get all the selected cards on the current hand
		/// </summary>
		/// <returns>A cardpile concisting of all the selected cards on the current hand</returns>
		public CardPile GetSelectedCards()
		{
			return m_CurrentHand.GetSelectedCards();
		}
		
		/// <summary>
		/// Checks that all the currently selected cards on the current hand can be selected
		/// </summary>
		public void CheckAllSelectedCards()
		{
			m_CurrentHand.CheckAllSelectedCards();
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// The current hand (get)
		/// </summary>
		public Hand CurrentHand
		{
			get
			{
				return m_CurrentHand.ProxyHand;
			}
		}
		
		/// <summary>
		/// Hand 2 (get)
		/// </summary>
		public Hand HandPhase2
		{
			get
			{
				return m_HandPhase2;
			}
		}
		
		/// <summary>
		/// The controler this player is assigned to (get)
		/// </summary>
		public PoomanControl Controler
		{
			get
			{
				return m_Controler;
			}
		}
		
		/// <summary>
		/// The area this player has been assigned to (get)
		/// </summary>
		public CardArea Area
		{
			get
			{
				return m_Area;
			}
		}
		
		#endregion
	}
}
